﻿using Autofac;
using CQRSFramework.Common.Components;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace CQRSFramework.Common.Autofac
{
    public class AutofacObjectContainer : IObjectContainer
    {
        private readonly ContainerBuilder _containerBuilder;
        private IContainer _container;
        public AutofacObjectContainer(ContainerBuilder containerBuilder)
        {
            _containerBuilder = containerBuilder;
        }
        public ContainerBuilder ContainerBuilder
        {
            get
            {
                return _containerBuilder;
            }
        }
        public IContainer Container
        {
            get
            {
                return _container;
            }
        }
        public void RegisterType(Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton)
        {
            var registrationBuilder = _containerBuilder.RegisterType(implementationType);
            if (serviceName != null)
            {
                registrationBuilder.Named(serviceName, implementationType);
            }
            if (life == LifeStyle.Singleton)
            {
                registrationBuilder.SingleInstance();
            }
        }

        public void RegisterType(Type serviceType, Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton)
        {
            var registrationBuilder = _containerBuilder.RegisterType(implementationType).As(serviceType);
            if (serviceName != null)
            {
                registrationBuilder.Named(serviceName, serviceType);
            }
            if (life == LifeStyle.Singleton)
            {
                registrationBuilder.SingleInstance();
            }
        }

        public void Register<TService, TImplementer>(string serviceName, LifeStyle life) where TService : class
            where TImplementer : class, TService
        {
            var registrationBuilder = _containerBuilder.RegisterType<TImplementer>().As<TService>();
            if (serviceName != null)
            {
                registrationBuilder.Named<TService>(serviceName);
            }
            if (life == LifeStyle.Singleton)
            {
                registrationBuilder.SingleInstance();
            }
        }

        public void RegisterInstance<TService, TImplementer>(TImplementer instance, string serviceName) where TService : class
            where TImplementer : class, TService
        {
            var registrationBuilder = _containerBuilder.RegisterInstance(instance).As<TService>().SingleInstance();
            if (serviceName != null)
            {
                registrationBuilder.Named<TService>(serviceName);
            }
        }

        public void Build()
        {
            _container = _containerBuilder.Build();
        }

        public TService Resolve<TService>() where TService : class
        {
            return _container.Resolve<TService>();
        }

        public object Resolve(Type serviceType)
        {
            return _container.Resolve(serviceType);
        }

        public object ResolveOptional(Type serviceType)
        {
            return _container.ResolveOptional(serviceType);
        }

        public TService ResolveNamed<TService>(string serviceName) where TService : class
        {
            return _container.ResolveNamed<TService>(serviceName);
        }

        public object ResolveNamed(string serviceName, Type serviceType)
        {
            return _container.ResolveNamed(serviceName, serviceType);
        }

        public void RegisterGeneric(Type serviceType, Type implementationType, string serviceName = null, LifeStyle life = LifeStyle.Singleton)
        {
            var registrationBuilder = _containerBuilder.RegisterGeneric(implementationType).As(serviceType);
            if (serviceName != null)
            {
                registrationBuilder.Named(serviceName, serviceType);
            }
            if (life == LifeStyle.Singleton)
            {
                registrationBuilder.SingleInstance();
            }
        }

        public IEnumerable<object> ResolveAll(Type serviceType)
        {
            var types = typeof(IEnumerable<>).MakeGenericType(serviceType);
            return ((IEnumerable)_container.Resolve(types)).OfType<object>().ToList();
        }
    }
}
